using System;
using System.Collections.Generic;
using System.Xml;
using System.Data;
using System.Diagnostics;
using Adoor.Expression;
using Adoor.Object;
using Adoor.Object.Entity;
using Adoor.Relational;
using Adoor.Data;  // For SmartKey


namespace Adoor.Object.Relational
{
    public class AutoIncrementKeyFactory<TEntity> : CustomKeyFactory<TEntity>
    {
        object nextKey = null;
        protected string sqlStatement;
        protected int increment;

        public AutoIncrementKeyFactory(Adoor.Object.Domain.EntityData entityData, XmlNode metadata)
            : base(entityData, metadata)
        {
            //			// TODO: temp initializations. parameterize in the XML
            //			Adoor.Object.Relational.EntityTableFactory tableFactory = this.EntityFactory as Adoor.Object.Relational.EntityTableFactory;
            //#if Oracle
            //			this.sqlStatement = "select MAX(To_Number(" + this.PrimaryKey + ")) from " + tableFactory.TableName;
            //#else
            //			this.sqlStatement = "select max(" + this.PrimaryKey + ") from " + tableFactory.TableName;
            //#endif
            this.increment = 1;

            Debug.Assert(metadata.SelectSingleNode("@SqlStatement") == null, "SqlStatement => sqlStatement");
            XmlNode sqlNode = metadata.SelectSingleNode("@sqlStatement");
            if (sqlNode == null)
                throw new Exception("Attribute " + entityData.EntityType.Name + "/mapping:entity/mapping:key/@sqlStatement not found");
            this.sqlStatement = sqlNode.Value;

            Debug.Assert(metadata.SelectSingleNode("@Step") == null, "Step => step");
            XmlNode incNode = metadata.SelectSingleNode("@step");
            if (incNode != null)
            {
                try
                {
                    this.increment = Int32.Parse(incNode.Value);
                }
                catch (Exception e)
                {
                    //System.Diagnostics.Trace.WriteLine(e.Message, "Error");
                    throw new Exception("Expecting integer value for attribute " + entityData.EntityType.Name + "/mapping:entity/mapping:key/@step", e);
                }
            }
        }

        public override void CreateKey(IEntityState state)
        {
            object key = this.nextKey;
            int result;
            if (key == null)
            {
                IEntityFactory factory = (IEntityFactory)this.EntityData.GetService(typeof(IEntityFactory));
                Adoor.Object.Relational.EntityTableFactory<TEntity> tableFactory = factory as Adoor.Object.Relational.EntityTableFactory<TEntity>;
                if (tableFactory == null)
                    throw new ArgumentException(this.GetType().Name + "::CreateKey only works with factories of type Adoor.Object.Relational.EntityTableFactory");
                //TODO: IDataSource datasource = Adoor.Object.Disconnected.ObjectContext.ContextStorage.GetPersistentValues("DataSource") as IDataSource;
                //using (IDbConnection connection = datasource.CreateConnection()) 
                //{
                //    IDbCommand command = connection.CreateCommand();
                //    command.CommandTimeout = 0;
                //    command.CommandText = this.sqlStatement;
                //    //System.Diagnostics.Trace.WriteLine(command.CommandText, "KEY");
                //    connection.Open();
                //    object max = command.ExecuteScalar();
                //    if (max == null || max == DBNull.Value)
                //        result = this.increment;
                //    else
                //        result = Convert.ToInt32(max) + this.increment;
                //}

                //HACK: In order to compile
                result = -1;
            }
            else
                result = Convert.ToInt32(key);
            this.nextKey = result + this.increment;
            ((IRelationalEntityState)state)[this.PrimaryKey] = result;
        }
    }

}
